﻿using System;
using System.Collections.Generic;

using System.Text;

namespace Fetion.Core
{
    /// <summary>
    /// 数据流写入对像
    /// </summary>
    public class BufferWriter 
    {
        internal Queue<DataBuffer> Buffers = new Queue<DataBuffer>(100);
     
        private int mCount;
       
        private IByteConverter mByteConverter = new ByteConverter();  
      
        const int ZERO = 0;
        /// <summary>
        /// 获取流写入的字节数
        /// </summary>
        public int Count
        {
            get
            {
                return mCount;
            }
        }
        /// <summary>
        /// 写入一个int32,4个byte,并返回写入所在的buffer位置
        /// </summary>
        /// <returns>IList'ByteArraySegment</returns>
        public ByteArraySegment WriteHeadSize()
        {

            byte[] valuedata = mByteConverter.GetBytes(ZERO);
            return WriteReturnSegment(valuedata, 0, 4);
        }
        /// <summary>
        /// 把一个int32更新到指定buffer的位置，4个byte
        /// </summary>
        /// <param name="size">int数值</param>
        /// <param name="refdata">更新buffer所在位置</param>
        public void SetHeadSize(int size, ByteArraySegment refdata)
        {
            byte[] valuedata = BitConverter.GetBytes(size);
            Buffer.BlockCopy(valuedata, 0, refdata.Array, refdata.Offset, valuedata.Length);

        }
        /// <summary>
        /// 构建流写入对像
        /// </summary>
        /// <param name="coding">字符编码</param>
        public BufferWriter(System.Text.Encoding coding)
        {
            Coding = coding;

      
          
        }
        /// <summary>
        /// 获取或设置字符编码
        /// </summary>
        public Encoding Coding
        {
            get;
            set;
        }
 
       
        /// <summary>
        /// 写入一个byte
        /// </summary>
        /// <param name="value">byte</param>
        public void Write(byte value)
        {
            
            Write(new byte[]{value},0,1);
        }
        /// <summary>
        /// 写入一个时间，转成对应的long写入8个byte
        /// </summary>
        /// <param name="datetime">datetime</param>
        public void Write(DateTime datetime)
        {
            Write(mByteConverter.GetBytes(datetime.Ticks), 0, 8);
        }
        private bool WriteArrayLength(Array value)
        {
            if (value == null)
            {
                Write(ZERO);

            }
            else
            {
                Write(value.Length);
            }
            return value != null && value.Length > 0;
        } 
        /// <summary>
        /// 写入一个时间数组，先写入一个数据长度int32(4个byte),然后分别写入每个datetime(8个byte)
        /// </summary>
        /// <param name="value">DateTime[]</param>
        public void Write(DateTime[] value)
        {
            if (WriteArrayLength(value))
            {
                for (int i = 0; i < value.Length; i++)
                {
                    Write(value[i]);
                }
            }
        }
        private bool WriteIListLength<T>(IList<T> values)
        {
            if (values == null || values.Count == 0)
            {
                Write(ZERO);
                return false;
            }
            else
            {
                Write(values.Count);
                return true;
            }
        }
        /// <summary>
        /// 写入一个时间列表,先写入一个数据长度int32(4个byte),然后分别写入每个datetime(8个byte)
        /// </summary>
        /// <param name="values">IList'datetime</param>
        public void Write(IList<DateTime> values)
        {
            if (WriteIListLength<DateTime>(values))
            {

                for (int i = 0; i < values.Count; i++)
                {
                    Write(values[i]);
                }
            }

        }
        /// <summary>
        /// 写入一个float(4byte)
        /// </summary>
        /// <param name="value">float</param>
        public  void Write(float value)
        {
            if (EnabledVariant)
                WriteVariant(BitConverter.ToInt32(BitConverter.GetBytes(value),0));
            else
                Write(mByteConverter.GetBytes(value), 0, 4);
        }
        /// <summary>
        /// 定入一个float数组，先写入一个数组长度int32(4byte),然后分别写入每个fload(4byte)
        /// </summary>
        /// <param name="value">float[]</param>
        public void Write(float[] value)
        {
            if (WriteArrayLength(value))
            {
                for (int i = 0; i < value.Length; i++)
                {
                    Write(value[i]);
                }
            }
        }
        /// <summary>
        /// 定入一个float列表，先写入一个数组长度int32(4byte),然后分别写入每个fload(4byte)
        /// </summary>
        /// <param name="values">IList'float</param>
        public void Write(IList<float> values)
        {
            if (WriteIListLength<float>(values))
            {
                for (int i = 0; i < values.Count; i++)
                {
                    Write(values[i]);
                }
            }

        }
        /// <summary>
        /// 写入一个bool(1byte)
        /// </summary>
        /// <param name="value">bool</param>
        public void Write(bool value)
        {
            Write(mByteConverter.GetBytes(value), 0, 1);
        }
        /// <summary>
        /// 写入一个bool数组，先写入数组长度int32(4byte),然后分别写入每个bool(1byte)
        /// </summary>
        /// <param name="value">bool[]</param>
        public void Write(bool[] value)
        {
            if (WriteArrayLength(value))
            {
                for (int i = 0; i < value.Length; i++)
                {
                    Write(value[i]);
                }
            }
        }
        /// <summary>
        /// 写入一个bool列表，先写入数组长度int32(4byte),然后分别写入每个bool(1byte)
        /// </summary>
        /// <param name="values">IList'bool</param>
        public void Write(IList<bool> values)
        {
            if (WriteIListLength<bool>(values))
            {
                for (int i = 0; i < values.Count; i++)
                {
                    Write(values[i]);
                }
            }

        }
        /// <summary>
        /// 写入一个char(2byte)
        /// </summary>
        /// <param name="value">char</param>
        public void Write(char value)
        {
            Write(mByteConverter.GetBytes(value), 0, 2);
        }
        /// <summary>
        /// 写入一个char数组，先写入数组长度int32(4byte),然后分别写入每个char(2byte)
        /// </summary>
        /// <param name="value">char[]</param>
        public void Write(char[] value)
        {
            if (WriteArrayLength(value))
            {
                for (int i = 0; i < value.Length; i++)
                {
                    Write(value[i]);
                }
            }
        }
        /// <summary>
        /// 写入一个char列表，先写入数组长度int32(4byte),然后分别写入每个char(2byte)
        /// </summary>
        /// <param name="values">IList'char</param>
        public void Write(IList<char> values)
        {
            if (WriteIListLength<char>(values))
            {
                for (int i = 0; i < values.Count; i++)
                {
                    Write(values[i]);
                }
            }

        }
        /// <summary>
        /// 定入一个double(8byte)
        /// </summary>
        /// <param name="value">double</param>
        public  void Write(double value)
        {

            if (EnabledVariant)
                WriteVariant(BitConverter.ToInt64(BitConverter.GetBytes(value),0));
            else
                Write(mByteConverter.GetBytes(value), 0, 8);
        }
        /// <summary>
        /// 写入一个double数组，先写入数组长度int32(4byte),然后分别写入每个double(8byte)
        /// </summary>
        /// <param name="value">double[]</param>
        public void Write(double[] value)
        {
            if (WriteArrayLength(value))
            {
                for (int i = 0; i < value.Length; i++)
                {
                    Write(value[i]);
                }
            }
        }
        /// <summary>
        /// 写入一个double列表，先写入数组长度int32(4byte),然后分别写入每个double(8byte)
        /// </summary>
        /// <param name="values">IList'double</param>
        public void Write(IList<double> values)
        {
            if (WriteIListLength<double>(values))
            {
                for (int i = 0; i < values.Count; i++)
                {
                    Write(values[i]);
                }
            }

        }
        /// <summary>
        /// 写入一个int16(2byte)
        /// </summary>
        /// <param name="value">int16</param>
        public void Write(Int16 value)
        {
            Write(mByteConverter.GetBytes(value), 0, 2);
        }
        /// <summary>
        /// 写入一个int16数组，先写入数组长度int32(4byte),然后分别写入每个int16(2byte)
        /// </summary>
        /// <param name="value">int16[]</param>
        public void Write(Int16[] value)
        {
            if (WriteArrayLength(value))
            {
                for (int i = 0; i < value.Length; i++)
                {
                    Write(value[i]);
                }
            }
        }
        /// <summary>
        /// 写入一个int16列表，先写入数组长度int32(4byte),然后分别写入每个int16(2byte)
        /// </summary>
        /// <param name="values">IList'int16</param>
        public void Write(IList<Int16> values)
        {
            if (WriteIListLength<Int16>(values))
            {
                for (int i = 0; i < values.Count; i++)
                {
                    Write(values[i]);
                }
            }

        }
        /// <summary>
        /// 定入一个int32(4byte)
        /// </summary>
        /// <param name="value">int32</param>
        public void Write(Int32 value)
        {
            if (EnabledVariant)
            {
                WriteVariant(value);
            }
            else
            {
                Write(mByteConverter.GetBytes(value), 0, 4);
            }
        }
        /// <summary>
        /// 写入一个int32数组，先写入数组长度int32(4byte),然后分别写入每个int32(4byte)
        /// </summary>
        /// <param name="value">int32[]</param>
        public void Write(Int32[] value)
        {
            if (WriteArrayLength(value))
            {
                for (int i = 0; i < value.Length; i++)
                {
                    Write(value[i]);
                }
            }
        }
        /// <summary>
        /// 写入一个int32列表，先写入数组长度int32(4byte),然后分别写入每个int32(4byte)
        /// </summary>
        /// <param name="values">IList'int32</param>
        public void Write(IList<Int32> values)
        {
            if (WriteIListLength<Int32>(values))
            {
                for (int i = 0; i < values.Count; i++)
                {
                    Write(values[i]);
                }
            }

        }
        /// <summary>
        /// 写入一个int64(8byte)
        /// </summary>
        /// <param name="value">int64</param>
        public void Write(Int64 value)
        {
            if (EnabledVariant)
                WriteVariant(value);
            else
                Write(mByteConverter.GetBytes(value), 0, 8);
        }
        /// <summary>
        /// 写入一个int64列表，先写入数组长度int32(4byte),然后分别写入每个int64(8byte)
        /// </summary>
        /// <param name="value">int64[]</param>
        public void Write(Int64[] value)
        {
            if (WriteArrayLength(value))
            {
                for (int i = 0; i < value.Length; i++)
                {
                    Write(value[i]);
                }
            }
        }
        /// <summary>
        /// 写入一个int64列表，先写入数组长度int32(4byte),然后分别写入每个int64(8byte)
        /// </summary>
        /// <param name="values">IList'int64</param>
        public void Write(IList<Int64> values)
        {
            if (WriteIListLength<Int64>(values))
            {
                for (int i = 0; i < values.Count; i++)
                {
                    Write(values[i]);
                }
            }

        }
        /// <summary>
        /// 写入一个byte数组，先写入数组长度int32(4byte),然后写入byte[]
        /// </summary>
        /// <param name="value">byte[]</param>
        public void Write(byte[] value)
        {
            int length = 0;
            if (value != null && value.Length>0)
            {
                length = value.Length;
            }
            Write(length);
            if (length > 0)
            {
                Write(value,0,value.Length);
            }
           
        }

        

       /// <summary>
        /// 根据BufferWriter的编码写入一个string,先写入编码byte[]的长度int32(4byte)，然后再写入具体编码的byte[]
       /// </summary>
       /// <param name="value">string</param>
        public void Write(string value)
        {

            if (string.IsNullOrEmpty(value))
            {
                Write(ZERO);
            }
            else
            {

                byte[] data = Coding.GetBytes(value);
                Write(data.Length);
                Write(data, 0, data.Length);


            }
        }
        /// <summary>
        /// 写入一个string数组，先写入数组长度int32(4byte),然后分别写入每个string
        /// </summary>
        /// <param name="value">string[]</param>
        public void Write(string[] value)
        {
            if (WriteArrayLength(value))
            {
                for (int i = 0; i < value.Length; i++)
                {
                    Write(value[i]);
                }
            }
        }
        /// <summary>
        /// 写入一个string列表，先写入列表长度int32(4byte),然后分别写入每个string
        /// </summary>
        /// <param name="values">IList'string</param>
        public void Write(IList<string> values)
        {
            if (WriteIListLength<string>(values))
            {
                for (int i = 0; i < values.Count; i++)
                {
                    Write(values[i]);
                }
            }

        }
        /// <summary>
        /// 写入一个IMessage对象
        /// </summary>
        /// <param name="obj">IMessage</param>
        public void Write(IMessage obj)
        {
            obj.Save(this);
        }
        /// <summary>
        /// 定入一个IMessage对象列表
        /// </summary>
        /// <typeparam name="T">消息类型</typeparam>
        /// <param name="objs">IList'T</param>
        public void Write<T>(IList<T> objs) where T:IMessage
        {
            if (objs == null)
            {
                Write(0);
                return;
            }
            Write(objs.Count);
            for (int i = 0; i < objs.Count; i++)
            {
                Write(objs[i]);
            }

        }
        private int _count;
        private int _sindex;
        /// <summary>
        /// 写入一byte[],指定写入的起始位置和长度
        /// </summary>
        /// <param name="value">byte[]</param>
        /// <param name="start">开始位置</param>
        /// <param name="length">写入长度</param>
        public void Write(byte[] value, int start, int length)
        {
            _count = 0;
            _sindex = start;
            _count = length;
            byte[] tmpdata = new byte[length];
            Buffer.BlockCopy(value, start, tmpdata, 0, length);
            DataBuffer db = new DataBuffer(tmpdata);
            Buffers.Enqueue(db);
            mCount += _count;

        }
       
        /// <summary>
        /// 写一个byte数据,并返回写入相应buffer的引用
        /// </summary>
        /// <param name="value">byte[]</param>
        /// <param name="start">开始位置</param>
        /// <param name="length">写入长度</param>
        /// <returns>IList'ByteArraySegment </returns>
        public ByteArraySegment WriteReturnSegment(byte[] value, int start, int length)
        {
            ByteArraySegment result = new ByteArraySegment();
           
            byte[] tmpdata = new byte[length];
            Buffer.BlockCopy(value, start, tmpdata, 0, length);
            DataBuffer db = new DataBuffer(tmpdata);
            Buffers.Enqueue(db);
            mCount += length;
            result.SetInfo(tmpdata, 0, tmpdata.Length);
            return result;
        }

        #region Variant
        /// <summary>
        /// 以变长的方式写入一个int
        /// </summary>
        /// <param name="value">int</param>
        private void WriteVariant(int value)
        {
            WriteUInt32Variant(Zig(value));
            Write(_UintVariantData.Array, 0, _UintVariantData.Count);
        }
        /// <summary>
        /// 以变长的方式写入一个long
        /// </summary>
        /// <param name="value">long</param>
        private void WriteVariant(long value)
        {
            WriteUInt64Variant(Zig(value));
            Write(_UlongVariantData.Array, 0, _UlongVariantData.Count);
        }
        /// <summary>
        /// 是否开启Variant方式写入数字，默认是false
        /// </summary>
        public bool EnabledVariant = false;
        private uint Zig(int value)
        {
            return (uint)((value << 1) ^ (value >> 31));
        }
        private ulong Zig(long value)
        {
            return (ulong)((value << 1) ^ (value >> 63));
        }
        private ByteArraySegment _UintVariantData = new ByteArraySegment(5);
        private void WriteUInt32Variant(uint value)
        {

            int count = 0;
            do
            {
                _UintVariantData.Array[count] = (byte)((value & 0x7F) | 0x80);
                count++;
            } while ((value >>= 7) != 0);
            _UintVariantData.Array[count - 1] &= 0x7F;
            _UintVariantData.SetInfo(0, count);
        }
        private ByteArraySegment _UlongVariantData = new ByteArraySegment(10);
        private void WriteUInt64Variant(ulong value)
        {
            int count = 0;
            do
            {
                _UlongVariantData.Array[count] = (byte)((value & 0x7F) | 0x80);
                count++;
            } while ((value >>= 7) != 0);
            _UlongVariantData.Array[count - 1] &= 0x7F;
            _UlongVariantData.SetInfo(0, count);
        }
        #endregion
    
    }
}
